﻿using H.Utils.DataStruct;
using System.IO;
using System.Net.Sockets;
using System.Text;

namespace H.Net.Nets
{
    /// <summary>
    /// 通过已经建立的Socket链接,将数据封装成帧
    /// </summary>
    internal class HFrameStream : Stream
    {
        /// <summary>
        /// 网络流
        /// </summary>
        private readonly NetworkStream _NetworkStream;

        /// <summary>
        /// 二进制写入
        /// </summary>
        private readonly BinaryReader _BinaryReader;

        /// <summary>
        /// 二进制读取
        /// </summary>
        private readonly BinaryWriter _BinaryWriter;

        /// <summary>
        /// HWebFrame缓冲池
        /// </summary>
        private readonly CommonPool<HWebFrame> _Pool = new CommonPool<HWebFrame>();

        ///<inheritdoc/>
        public override bool CanRead => _NetworkStream.CanRead;

        ///<inheritdoc/>
        public override bool CanSeek => _NetworkStream.CanSeek;

        ///<inheritdoc/>
        public override bool CanWrite => _NetworkStream.CanWrite;

        ///<inheritdoc/>
        public override long Length => _NetworkStream.Length;

        ///<inheritdoc/>
        public override long Position { get => _NetworkStream.Position; set => _NetworkStream.Position = value; }

        ///<inheritdoc/>
        public override void Flush()
        {
            _NetworkStream.Flush();
        }

        /// <summary>
        /// 初始化一个HFrame流
        /// </summary>
        /// <param name="socket"></param>
        public HFrameStream(Socket socket)
        {
            _NetworkStream = new NetworkStream(socket);
            _BinaryReader = new BinaryReader(_NetworkStream);
            _BinaryWriter = new BinaryWriter(_NetworkStream);
        }

        ///<inheritdoc/>
        public override int Read(byte[] buffer, int offset, int count)
        {
            return _BinaryReader.Read(buffer, offset, count);
        }

        ///<inheritdoc/>
        public override long Seek(long offset, SeekOrigin origin)
        {
            return _NetworkStream.Seek(offset, origin);
        }

        ///<inheritdoc/>
        public override void SetLength(long value)
        {
            _NetworkStream.SetLength(value);
        }

        ///<inheritdoc/>
        public override void Write(byte[] buffer, int offset, int count)
        {
            _BinaryWriter.Write(buffer, offset, count);
        }

        /// <summary>
        /// 向网络流中写入一个帧
        /// </summary>
        /// <param name="frame"></param>
        public void Write(HWebFrame frame)
        {
            _BinaryWriter.Write(frame.TopicID);
            _BinaryWriter.Write(frame.TypeID);
            _BinaryWriter.Write(frame.DataLength);
            _BinaryWriter.Write(frame.Buffer, 0, frame.DataLength);
        }

        /// <summary>
        /// 向网络流中写入一个帧(不携带数据)
        /// </summary>
        /// <param name="topicID">主题ID</param>
        /// <param name="typeID">类型ID</param>
        public void Write(int topicID, int typeID)
        {
            _BinaryWriter.Write(topicID);
            _BinaryWriter.Write(typeID);
            _BinaryWriter.Write(0);
        }

        /// <summary>
        /// 向网络流中写入一个帧
        /// </summary>
        /// <param name="topicID">主题ID</param>
        /// <param name="typeID">类型ID</param>
        /// <param name="dataLength">数据长度</param>
        /// <param name="buffer">数据缓冲区</param>
        public void Write(int topicID, int typeID, int dataLength, byte[] buffer)
        {
            _BinaryWriter.Write(topicID);
            _BinaryWriter.Write(typeID);
            _BinaryWriter.Write(dataLength);
            _BinaryWriter.Write(buffer, 0, dataLength);
        }

        /// <summary>
        /// 向网络流中写入一个帧
        /// </summary>
        /// <param name="topicID">主题ID</param>
        /// <param name="typeID">类型ID</param>
        /// <param name="dataLength">数据长度</param>
        public void Write(int topicID, int typeID, string message)
        {
            _BinaryWriter.Write(topicID);
            _BinaryWriter.Write(typeID);
            HWebFrame frame = _Pool.Malloc();
            int dataLength = Encoding.UTF8.GetBytes(message, 0, message.Length, frame.EnsureBufferSize(Encoding.UTF8.GetMaxByteCount(message.Length)), 0);
            _BinaryWriter.Write(dataLength);
            _BinaryWriter.Write(frame.Buffer, 0, dataLength);
            _Pool.Free(frame);
        }


        /// <summary>
        /// 从网络流中读取一个帧
        /// </summary>
        /// <returns></returns>
        public HWebFrame Read()
        {
            HWebFrame frame = _Pool.Malloc();
            frame.TopicID = _BinaryReader.ReadInt32();
            frame.TypeID = _BinaryReader.ReadInt32();
            frame.DataLength = _BinaryReader.ReadInt32();
            frame.EnsureBufferSize(frame.DataLength);
            int offset = 0;
            while (offset < frame.DataLength)
            {
                offset += _BinaryReader.Read(frame.Buffer, offset, frame.DataLength - offset);
            }
            return frame;
        }

        public void FreeFrame(HWebFrame frame)
        {
            _Pool.Free(frame);
        }
    }
}
